use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::time::Duration;

pub type StringListener = Box<dyn Fn(String) + Send + Sync + 'static>;
pub type IntListener = Box<dyn Fn(i64) + Send + Sync + 'static>;

#[derive(Default)]
pub struct Engine {
    string_listener_lock: Arc<RwLock<Option<StringListener>>>,
    int_listener_lock: Arc<RwLock<Option<IntListener>>>,
}

impl Engine {
    pub fn new() -> Self {
        Engine {
            ..Default::default()
        }
    }
}

impl Engine {
    pub fn set_string_listener(&self, listener_opt: Option<StringListener>) {
        let mut writer = self.string_listener_lock.write().unwrap();
        *writer = listener_opt;
    }

    pub fn set_int_listener(&self, listener_opt: Option<IntListener>) {
        let mut writer = self.int_listener_lock.write().unwrap();
        *writer = listener_opt;
    }
}

impl Engine {
    pub fn call_listeners(&self, count: i64, need_sleep: bool) {
        // 手动创建 Tokio Runtime
        let rt = tokio::runtime::Runtime::new().unwrap();
        rt.block_on(async {
            self.call_listeners_inner(count,need_sleep).await;
        });
    }

    async fn call_listeners_inner(&self, count: i64, need_sleep: bool) {
        for i in 0..count {
            // 使用 `tokio::spawn` 创建两个异步任务
            let string_listener_lock_clone = self.string_listener_lock.clone();
            tokio::spawn(async move {
                let string_listener_lock = string_listener_lock_clone.read().unwrap();
                if let Some(string_listener) = string_listener_lock.as_ref() {
                    string_listener(format!("{}", i));
                }
            });

            let int_listener_lock_clone = self.int_listener_lock.clone();
            tokio::spawn(async move {
                let int_listener_lock = int_listener_lock_clone.read().unwrap();
                if let Some(int_listener) = int_listener_lock.as_ref() {
                    int_listener(i);
                }
            });

            if need_sleep {
                let rand = rand::random::<u64>() % 1000;
                tokio::time::sleep(Duration::from_millis(rand)).await;
            }
        }
    }
}
